#ifndef SHARE_VM_ADLC_FORMSSEL_HPP
#define SHARE_VM_ADLC_FORMSSEL_HPP

class Form;

class InstructForm;

class MachNodeForm;

class OperandForm;

class OpClassForm;

class AttributeForm;

class RegisterForm;

class PipelineForm;

class SourceForm;

class EncodeForm;

class Component;

class Constraint;

class Predicate;

class MatchRule;

class Attribute;

class Effect;

class ExpandRule;

class RewriteRule;

class ConstructRule;

class FormatRule;

class Peephole;

class EncClass;

class Interface;

class RegInterface;

class ConstInterface;

class MemInterface;

class CondInterface;

class Opcode;

class InsEncode;

class RegDef;

class RegClass;

class CodeSnippetRegClass;

class ConditionalRegClass;

class AllocClass;

class ResourceForm;

class PipeDesc;

class PipeClass;

class PeepMatch;

class PeepConstraint;

class PeepReplace;

class MatchList;

class ArchDesc;

class InstructForm : public Form {
private:
    bool _ideal_only;

    int _cisc_spill_operand;

    void set_cisc_spill_operand(uint op_index) { _cisc_spill_operand = op_index; }

    bool is_cisc_alternate;
    InstructForm *_cisc_spill_alternate;
    const char *cisc_reg_mask_name;
    InstructForm *_short_branch_form;
    bool _is_short_branch;
    bool _is_mach_constant;
    bool _needs_constant_base;
    uint _alignment;

public:
    const char *_ident;
    NameList _parameters;
    FormDict _localNames;
    MatchRule *matrule;
    Opcode *_opcode;
    char *_size;
    InsEncode *_insencode;
    InsEncode *_constant;
    bool _is_postalloc_expand;
    Attribute *_attribs;
    Predicate *_predicate;
    FormDict _effects;
    ExpandRule *_exprule;
    RewriteRule *_rewrule;
    FormatRule *_format;
    Peephole *_peephole;
    const char *_ins_pipe;

    uint *_uniq_idx;
    uint _uniq_idx_length;
    uint _num_uniq;
    ComponentList _components;

    bool _has_call;

    InstructForm(const char *id, bool ideal_only = false);

    InstructForm(const char *id, InstructForm *instr, MatchRule *rule);

    ~InstructForm();

    virtual InstructForm *is_instruction() const;

    virtual bool ideal_only() const;

    virtual bool sets_result() const;

    virtual bool needs_projections();

    virtual bool has_temps();

    virtual uint num_defs_or_kills();

    virtual bool expands() const;

    virtual bool postalloc_expands() const;

    virtual Peephole *peepholes() const;

    virtual void append_peephole(Peephole *peep);

    virtual bool is_pinned(FormDict &globals); // should be pinned inside block
    virtual bool is_projection(FormDict &globals); // node requires projection
    virtual bool is_parm(FormDict &globals); // node matches ideal 'Parm'
    // ideal opcode enumeration
    virtual const char *ideal_Opcode(FormDict &globals) const;

    virtual int is_expensive() const;     // node matches ideal 'CosD'
    virtual int is_empty_encoding() const; // _size=0 and/or _insencode empty
    virtual int is_tls_instruction() const; // tlsLoadP rule or ideal ThreadLocal
    virtual int is_ideal_copy() const;    // node matches ideal 'Copy*'
    virtual bool is_ideal_negD() const;    // node matches ideal 'NegD'
    virtual bool is_ideal_if() const;    // node matches ideal 'If'
    virtual bool is_ideal_fastlock() const; // node matches 'FastLock'
    virtual bool is_ideal_membar() const;  // node matches ideal 'MemBarXXX'
    virtual bool is_ideal_loadPC() const;  // node matches ideal 'LoadPC'
    virtual bool is_ideal_box() const;     // node matches ideal 'Box'
    virtual bool is_ideal_goto() const;    // node matches ideal 'Goto'
    virtual bool is_ideal_branch() const;  // "" 'If' | 'Goto' | 'LoopEnd' | 'Jump'
    virtual bool is_ideal_jump() const;    // node matches ideal 'Jump'
    virtual bool is_ideal_return() const;  // node matches ideal 'Return'
    virtual bool is_ideal_halt() const;    // node matches ideal 'Halt'
    virtual bool is_ideal_safepoint() const; // node matches 'SafePoint'
    virtual bool is_ideal_nop() const;     // node matches 'Nop'
    virtual bool is_ideal_control() const; // control node
    virtual bool is_vector() const;        // vector instruction

    virtual Form::CallType is_ideal_call() const; // matches ideal 'Call'
    virtual Form::DataType is_ideal_load() const; // node matches ideal 'LoadXNode'
    // Should antidep checks be disabled for this Instruct
    // See definition of MatchRule::skip_antidep_check
    bool skip_antidep_check() const;

    virtual Form::DataType is_ideal_store() const;// node matches ideal 'StoreXNode'
    bool is_ideal_mem() const { return is_ideal_load() != Form::none || is_ideal_store() != Form::none; }

    virtual uint two_address(FormDict &globals); // output reg must match input reg
    // when chaining a constant to an instruction, return 'true' and set opType
    virtual Form::DataType is_chain_of_constant(FormDict &globals);

    virtual Form::DataType is_chain_of_constant(FormDict &globals, const char *&opType);

    virtual Form::DataType is_chain_of_constant(FormDict &globals, const char *&opType, const char *&result_type);

    // Check if a simple chain rule
    virtual bool is_simple_chain_rule(FormDict &globals) const;

    // check for structural rematerialization
    virtual bool rematerialize(FormDict &globals, RegisterForm *registers);

    // loads from memory, so must check for anti-dependence
    virtual bool needs_anti_dependence_check(FormDict &globals) const;

    virtual int memory_operand(FormDict &globals) const;

    enum memory_operand_type {
        NO_MEMORY_OPERAND = -1,
        MANY_MEMORY_OPERANDS = 999999
    };


    // This instruction captures the machine-independent bottom_type
    // Expected use is for pointer vs oop determination for LoadP
    virtual bool captures_bottom_type(FormDict &globals) const;

    virtual const char *cost();      // Access ins_cost attribute
    virtual uint num_opnds(); // Count of num_opnds for MachNode class
    // Counts USE_DEF opnds twice.  See also num_unique_opnds().
    virtual uint num_post_match_opnds();

    virtual uint num_consts(FormDict &globals) const;// Constants in match rule
    // Constants in match rule with specified type
    virtual uint num_consts(FormDict &globals, Form::DataType type) const;

    // Return the register class associated with 'leaf'.
    virtual const char *out_reg_class(FormDict &globals);

    // number of ideal node inputs to skip
    virtual uint oper_input_base(FormDict &globals);

    // Does this instruction need a base-oop edge?
    int needs_base_oop_edge(FormDict &globals) const;

    // Build instruction predicates.  If the user uses the same operand name
    // twice, we need to check that the operands are pointer-eequivalent in
    // the DFA during the labeling process.
    Predicate *build_predicate();

    virtual void build_components(); // top-level operands
    // Return zero-based position in component list; -1 if not in list.
    virtual int operand_position(const char *name, int usedef);

    virtual int operand_position_format(const char *name);

    // Return zero-based position in component list; -1 if not in list.
    virtual int label_position();

    virtual int method_position();

    // Return number of relocation entries needed for this instruction.
    virtual uint reloc(FormDict &globals);

    const char *opnd_ident(int idx);  // Name of operand #idx.
    const char *reduce_result();

    // Return the name of the operand on the right hand side of the binary match
    // Return NULL if there is no right hand side
    const char *reduce_right(FormDict &globals) const;

    const char *reduce_left(FormDict &globals) const;

    // Base class for this instruction, MachNode except for calls
    virtual const char *mach_base_class(FormDict &globals) const;

    // Check if this instruction can cisc-spill to 'alternate'
    bool cisc_spills_to(ArchDesc &AD, InstructForm *alternate);

    InstructForm *cisc_spill_alternate() { return _cisc_spill_alternate; }

    int cisc_spill_operand() const { return _cisc_spill_operand; }

    bool is_cisc_alternate() const { return _is_cisc_alternate; }

    void set_cisc_alternate(bool val) { _is_cisc_alternate = val; }

    const char *cisc_reg_mask_name() const { return _cisc_reg_mask_name; }

    void set_cisc_reg_mask_name(const char *rm_name) { _cisc_reg_mask_name = rm_name; }

    // Output cisc-method prototypes and method bodies
    void declare_cisc_version(ArchDesc &AD, FILE *fp_cpp);

    bool define_cisc_version(ArchDesc &AD, FILE *fp_cpp);

    bool check_branch_variant(ArchDesc &AD, InstructForm *short_branch);

    bool is_short_branch() { return _is_short_branch; }

    void set_short_branch(bool val) { _is_short_branch = val; }

    bool is_mach_constant() const { return _is_mach_constant; }

    void set_is_mach_constant(bool x) { _is_mach_constant = x; }

    bool needs_constant_base() const { return _needs_constant_base; }

    void set_needs_constant_base(bool x) { _needs_constant_base = x; }

    InstructForm *short_branch_form() { return _short_branch_form; }

    bool has_short_branch_form() { return _short_branch_form != NULL; }

    // Output short branch prototypes and method bodies
    void declare_short_branch_methods(FILE *fp_cpp);

    bool define_short_branch_methods(ArchDesc &AD, FILE *fp_cpp);

    uint alignment() { return _alignment; }

    void set_alignment(uint val) { _alignment = val; }

    // Seach through operands to determine operands unique positions.
    void set_unique_opnds();

    uint num_unique_opnds() { return _num_uniq; }

    uint unique_opnds_idx(int idx) {
        if (_uniq_idx != NULL && idx > 0) {
            assert((uint) idx < _uniq_idx_length, "out of bounds");
            return _uniq_idx[idx];
        } else {
            return idx;
        }
    }

    const char *unique_opnd_ident(uint idx);  // Name of operand at unique idx.

    // Operands which are only KILLs aren't part of the input array and
    // require special handling in some cases.  Their position in this
    // operand list is higher than the number of unique operands.
    bool is_noninput_operand(uint idx) {
        return (idx >= num_unique_opnds());
    }

    // --------------------------- FILE *output_routines
    //
    // Generate the format call for the replacement variable
    void rep_var_format(FILE *fp, const char *rep_var);

    // Generate index values needed for determining the operand position
    void index_temps(FILE *fp, FormDict &globals, const char *prefix = "", const char *receiver = "");
    // ---------------------------

    virtual bool verify();           // Check consistency after parsing

    virtual void dump();             // Debug printer
    virtual void output(FILE *fp);   // Write to output files
};

class EncodeForm : public Form {
private:

public:
    NameList _eclasses;
    Dict _encClass;
};

class ConstructRule : public Form {
private:

public:
    char *_expr;
    char *_construct;

    ConstructRule(char *cnstr);

    ~ConstructRule();

    void dump();

    void output(FILE *fp);
};

class EncClass : public Form {
public:
    NameList _parameter_type;
    NameList _parameter_name;

    NameList _code;
    NameList _rep_vars;

    NameList _parameters;
    FormDict _localNames;

public:
    const char *_name;

    EncClass(const char *name);

    ~EncClass();

    void add_parameter(const char *parameter_type, const char *parameter_name);

    bool check_parameter_types(FormDict &globals);

    int rep_var_index(const char *rep_var);

    int num_args() { return _parameter_name.count(); }

    void add_code(const char *string_preceding_replacement_var);

    void add_rep_var(char *replacement_var);

    bool verify();

    void dump();

    void output(FILE *fp);
};

class MachNodeForm : public Form {
private:

public:
    char *_ident;
    const char *_machnode_pipe;

    MachNodeForm(char *id);

    ~MachNodeForm();

    virtual MachNodeForm *is_machnode() const;

    void dump();

    void output(FILE *fp);
};

class Opcode : public Form {
private:

public:
    char *_primary;
    char *_secondary;
    char *_tertiary;

    enum opcode_type {
        NOT_AN_OPCODE = -1,
        PRIMARY = 1,
        SECONDARY = 2,
        TERTIARY = 3
    };

    Opcode(char *primary, char *secondary, char *tertiary);

    ~Opcode();

    static Opcode::opcode_type as_opcode_type(const char *designator);

    void dump();

    void output(FILE *fp);

    bool print_opcode(FILE *fp, Opcode::opcode_type desired_opcode);
};

class InsEncode : public Form {
private:
    NameList _encoding;

public:
    InsEncode();

    ~InsEncode();

    NameAndList *add_encode(char *encode_method_name);

    void reset();

    const char *encode_class_iter();

    int current_encoding_num_args() {
        return ((NameAndList *) _encoding.current())->count();
    }

    const char *rep_var_name(InstructForm &inst,uint param_no);

    void dump();

    void output(FILE *fp);
};

class Effect : public Form {
private:

public:
    const char *_name;
    int _use_def;

    Effect(const char *name);

    ~Effect();

    virtual Effect *is_effect() const;

    bool is(int use_def_kill_enum) const;

    bool isa(int use_def_kill_enum) const;

    void dump();

    void output(FILE *fp);
};

class ExpandRule : public Form {
private:
    NameList _expand_instrs;
public:
    NameList _newopers;
    Dict _newopconst;

    void add_instruction(NameAndList *instruction_name_and_operand_list);

    void reset_instructions();

    NameAndList *iter_instructions();

    ExpandRule();

    ~ExpandRule();

    void dump();

    void output(FILE *fp);
};

class AttributeForm : public Form {
private:
    static int _insId;
    static int _opId;

    int id;

public:
    char *_attrname;
    int _atype;
    char *_attrdef;

    AttributeForm(char *attr, int type, char *attrdef);

    ~AttributeForm();

    virtual AttributeForm *is_attribute() const;

    int type() { return id; }

    static const char *_ins_cost;
    static const char *_op_cost;

    void dump();

    void output(FILE *fp);
};

class Component : public Form {
private:

public:
    const char *_name;
    const char *_type;
    int _usedef;

    Component(const char *name, const char *type, int usedef);

    ~Component();

    bool is(int use_def_kill_enum) const;

    bool isa(int use_def_kill_enum) const;

    int promote_use_def_into(int new_use_def);

    const char *base_type(FormDict &globals);

    void dump();

    void output(FILE *fp);

    const char getUsedefName();

public:
    enum use_def_enum {
        INVALID = 0x0,
        USE = 0x1,
        DEF = 0x2,
        USE_DEF = USE | DEF,
        KILL = 0x4,
        USE_KILL = USE | KILL,
        SYNTHETIC = 0x8,
        TEMP = USE | SYNTHETIC,
        TEMP_DEF = TEMP | DEF,
        CALL = 0x10
    };
};

class MatchNode : public Form {
private:

public:
    const char *_result;
    const char *_name;
    const char *opType;
    MatchNode *lChild;
    MatchNode *rChild;
    int _numleaves;
    ArchDesc &_AD;
    char *_internalop;
    int _commutative_id;

    MatchNode(ArchDesc &ad, const char *result = 0, const char *expr = 0, const char *opType = 0,
              MatchNode *lChild = NULL, MatchNode *rChild = NULL);

    MatchNode(ArchDesc &ad, MatchNode &mNode);

    MatchNode(ArchDesc &ad, MatchNode &mNode, int clone);

    ~MatchNode();

    bool find_name(const char *str, int &position) const;

    bool find_type(const char *str, int &position) const;

    virtual void append_components(FormDict &locals, ComponentList &components, bool def_flag = false) const;

    bool base_operand(uint &position, FormDict &globals,
                      const char *&result, const char *&name, const char *&opType) const;

    uint num_consts(FormDict &globals) const;

    uint num_const_ptrs(FormDict &globals) const;

    uint num_consts(FormDict &globals, Form::DataType type) const;

    int needs_ideal_memory_edge(FormDict &globals) const;

    int needs_base_oop_edge() const;

    void count_instr_names(Dict &names);

    int build_instr_pred(char *buf, const char *name, int cnt);

    void build_internalop();

    bool set_result() const;

    const char *reduce_right(FormDict &globals) const;

    const char *reduce_left(FormDict &globals) const;

    int cisc_spill_match(FormDict &globals, RegisterForm *registers,
                         MatchNode *mRule2, const char *&operand,
                         const char *&reg_type);

    int cisc_spill_merge(int left_result, int right_result);

    virtual bool equivalent(FormDict &globals, MatchNode *mNode2);

    void count_commutative_op(int &count);

    void swap_commutative_op(bool atroot, int count);

    void dump();

    void output(FILE *fp);
};

class MatchRule : public MatchNode {
private:

public:
    const char *machType;
    int _depth;
    char *_construct;
    int _numchilds;
    MatchRule *next;

    MatchRule(ArchDesc &ad);

    MatchRule(ArchDesc &ad, MatchRule *mRule);

    MatchRule(ArchDesc &ad, MatchNode *mroot, int depth, char *construct, int numleaves);

    ~MatchRule();

    virtual void append_components(FormDict &locals, ComponentList &components, bool def_flag = false) const;

    bool base_operand(uint &position, FormDict &globals,
                      const char *&result, const char *&name,
                      const char *&opType) const;

    bool is_base_register(FormDict &globals) const;

    Form::DataType is_base_constant(FormDict &globals) const;

    bool is_chain_rule(FormDict &globals) const;

    int is_ideal_copy() const;

    int is_expensive() const;

    bool is_ideal_if() const;

    bool is_ideal_fastlock() const;

    bool is_ideal_jump() const;

    bool is_ideal_membar() const;

    bool is_ideal_loadPC() const;

    bool is_ideal_box() const;

    bool is_ideal_goto() const;

    bool is_ideal_loopEnd() const;

    bool is_ideal_bool() const;

    bool is_vector() const;

    Form::DataType is_ideal_load() const;

    bool skip_antidep_check() const;

    Form::DataType is_ideal_store() const;

    int matchrule_cisc_spill_match(FormDict &globals, RegisterForm *registers,
                                   MatchRule *mRule2, const char *&operand,
                                   const char *&reg_type);

    virtual bool equivalent(FormDict &globals, MatchNode *mRule2);

    void matchrule_swap_commutative_op(const char *instr_ident, int count, int &match_rules_cnt);

    void dump();

    void output_short(FILE *fp);

    void output(FILE *fp);
};

class Attribute : public Form {
private:

public:
    char *_ident;
    char *_val;
    int _atype;

    int int_val(ArchDesc &ad);

    Attribute(char *id, char *val, int type);

    ~Attribute();

    void dump();

    void output(FILE *fp);
};

class FormatRule : public Form {
private:

public:
    NameList _strings;
    NameList _reg_vars;
    char *temp;

    FormatRule(char *temp);

    ~FormatRule();

    void dump();

    void output(FILE *fp);
};

#endif // SHARE_VM_ADLC_FORMSSEL_HPP